package net.asfun.jvalog.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Level;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import net.asfun.jvalog.misc.ThreadHelper;
import net.asfun.jvalog.po.Model;
import static net.asfun.jvalog.misc.Log.logger;

public class Jdoer<M> {
	
	private PersistenceManager pm;
	
	private Class<M> clazz = null;
	
	protected Jdoer(Class<M> clazz){
		this.clazz = clazz;
	}
	
	public void save(Model model) {
		pm = ThreadHelper.dba().connect();
		pm.makePersistent(model);
	}
	
	public M load(Object id) {
		try {
			pm = ThreadHelper.dba().connect();
			return pm.getObjectById(clazz, id);
		} catch (JDOObjectNotFoundException ex) {
			logger.warning(ex.getMessage());
			return null;
		}
	}
	
	public void remove(Object id) {
		try {
			pm = ThreadHelper.dba().connect();
			pm.deletePersistent(pm.getObjectById(clazz, id));
		} catch (JDOObjectNotFoundException ex) {
			logger.info("No " + clazz.getName() + " with id " + id + " exist to be deleted.");
		}
	}
	
	public Query prepareQuery() {
		pm = ThreadHelper.dba().connect();
		return pm.newQuery(clazz);
	}
	
	public M unique() {
		pm = ThreadHelper.dba().connect();
		return unique(pm.newQuery(clazz));
	}
	
	@SuppressWarnings("unchecked")
	public M unique(String condition) {
		Query q;
		pm = ThreadHelper.dba().connect();
		if (condition == null || "".equals(condition.trim()))
			q = pm.newQuery(clazz);
		else 
			q = pm.newQuery(clazz, condition);
		q.setUnique(true);
		try {
			return (M)q.execute();
		} catch (Exception e) {
			logger.log(Level.INFO, e.getMessage(), e.getCause());
			return null;
		}
	}
	
	@SuppressWarnings("unchecked")
	public M unique(Query query, Object... params) {
		query.setUnique(true);
		try {
			if ( params.length == 0 ) {
				return (M)query.execute();
			} 
			return (M)query.executeWithArray(params);
		} catch (Exception e) {
			logger.log(Level.INFO, e.getMessage(), e.getCause());
			return null;
		}
	}
	
	public Collection<M> all() {
		pm = ThreadHelper.dba().connect();
		return more(pm.newQuery(clazz));
	}
	
	@SuppressWarnings("unchecked")
	public Collection<M> more(String condition) {
		Query q;
		pm = ThreadHelper.dba().connect();
		if (condition == null || "".equals(condition.trim()))
			q = pm.newQuery(clazz);
		else 
			q = pm.newQuery(clazz, condition);
		try {
			return (Collection<M>)q.execute();
		} catch (Exception e) {
			logger.log(Level.SEVERE, e.getMessage(), e.getCause());
			return new ArrayList<M>();
		}
	}
	
	@SuppressWarnings("unchecked")
	public Collection<M> more(Query query, Object... params) {
		try {
			if ( params.length == 0 ) {
				return (Collection<M>)query.execute();
			}
			return (Collection<M>)query.executeWithArray(params);
		} catch (Exception e) {
			logger.log(Level.SEVERE, e.getMessage(), e.getCause());
			return new ArrayList<M>();
		}
	}
	
	public void execute(Query query, Object... params) {
		try {
			if ( params.length == 0 ) {
				query.execute();
			} else {
				query.executeWithArray(params);
			}
		} catch (Exception e) {
			logger.log(Level.SEVERE, e.getMessage(), e.getCause());
		}
	}

	@SuppressWarnings("unchecked")
	public void delete(Collection pcs) {
		try {
			pm = ThreadHelper.dba().connect();
			pm.deletePersistentAll(pcs);
		} catch (Exception e) {
			logger.log(Level.SEVERE, e.getMessage(), e.getCause());
		}
	}
	
	public void undo(Model model) {
		//TODO unchange the model's data
	}
	
	public void delete(Model model) {
		try {
			pm = ThreadHelper.dba().connect();
			pm.deletePersistent(model);
		} catch (Exception e) {
			logger.log(Level.WARNING, e.getMessage(), e.getCause());
		}
	}

	public void flush() {
		pm = ThreadHelper.dba().connect();
		pm.flush();
	}

}
